package sk.bielyvlk.vlkgps;

import java.util.Iterator;
import java.util.LinkedList;

import sk.bielyvlk.vlkgps.osd.Osd;
import sk.bielyvlk.vlkgps.osd.OsdButton;
import sk.bielyvlk.vlkgps.osd.OsdButtonEvent;
import sk.bielyvlk.vlkgps.osd.OsdWidget;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.graphics.Paint.Style;
import android.location.Location;
import android.location.LocationManager;
import android.util.AttributeSet;
import android.util.FloatMath;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

public class VlkGpsView extends View implements OsdButtonEvent {
	public static final String TAG = "vlkGPS.VlkGpsView";

	private Location actualLocation = new Location(LocationManager.GPS_PROVIDER);
	private Projection projection = new Projection();
	private boolean projectionNotSet = true;
	//private LinkedList<Coordinates> track = new LinkedList<Coordinates>();
	private LinkedList<WayPoint> waypoints = new LinkedList<WayPoint>();
	private boolean followLocation = true;
	private boolean showCompas = true;
	private float mapRotate = 0;
	private float compass = 0;

	private OsdButton zoomin;
	private OsdButton zoomout;
	private OsdButton rotateright;
	private OsdButton rotateleft;
	
	private int width = 0;
	private int height = 0;

	private Osd osd = new Osd();

	public VlkGpsView(Context context, AttributeSet attrs) {
		super(context, attrs);
		Log.d(TAG, "VlkGpsView");
		setFocusable(true);
		requestFocus();
		projection.setZoom(100);
		zoomin = new OsdButton(context, this, R.drawable.zoomin);
		zoomout = new OsdButton(context, this, R.drawable.zoomout);
		rotateright = new OsdButton(context, this, R.drawable.rotateright);
		rotateleft = new OsdButton(context, this, R.drawable.rotateleft);
		osd.addWidget(zoomin);
		osd.addWidget(zoomout);
		osd.addWidget(rotateright);
		osd.addWidget(rotateleft);
		setBackgroundColor(0xff000000);
	}
	
	public void setActualLocation(Location location) {
		actualLocation.set(location);
		if (projectionNotSet || followLocation) {
			projectionNotSet = false;
			projection.setCenter(location);
		}
		invalidate();
	}
	
	public Location getActualLocation() {
		return actualLocation;
	}
	
	public void follow() {
		followLocation = true;
	}
	
	public void setCompass(float compas) {
		this.compass = compas;
		invalidate();
	}
	
	public void addWaypoint (WayPoint waypoint) {
		waypoints.add(waypoint);
	}

	@Override
	protected void onDraw(Canvas canvas) {
		if (width != getWidth() || height != getHeight()) {
			width = getWidth();
			height = getHeight();
			zoomin.setPosition(width - 64, height - 83);
			zoomout.setPosition(width - 128, height - 83);
			rotateright.setPosition(0, height - 83);
			rotateleft.setPosition(64, height - 83);
		}
		Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG | Paint.DITHER_FLAG);
		/* draw map */
		canvas.save();
		canvas.translate(width / 2, height / 2);
		canvas.rotate(-mapRotate);
		/* earth */
		paint.setStrokeWidth(2);
		if (projection.getZoom() * height * 2 > Coordinates.REARTH) {
			paint.setColor(0xff006699);
			paint.setStyle(Paint.Style.STROKE);
			canvas.drawCircle(0, 0, (float)(Coordinates.REARTH / projection.getZoom()), paint);
			paint.setStyle(Paint.Style.FILL);
			paint.setColor(0xffff0000);
			projection.calcCoordinates(new Coordinates(0, 90));
			if (projection.isVisible()) canvas.drawCircle(projection.getX(), - projection.getY(), 6, paint);
			else canvas.drawCircle(projection.getX(), - projection.getY(), 2, paint);
			paint.setColor(0xff0077ff);
			projection.calcCoordinates(new Coordinates(0, -90));
			if (projection.isVisible()) canvas.drawCircle(projection.getX(), - projection.getY(), 6, paint);
			else canvas.drawCircle(projection.getX(), - projection.getY(), 2, paint);
		}
		/* way points */
		paint.setStyle(Style.FILL);
		paint.setTextSize(13);
		paint.setTypeface(Typeface.DEFAULT_BOLD);
		paint.setTextAlign(Paint.Align.CENTER);
		paint.setColor(0xffaabbcc);
		float b = paint.getFontMetrics().bottom;
		Iterator<WayPoint> it = waypoints.iterator();
		while (it.hasNext()) {
			WayPoint waypoint = it.next();
			projection.calcCoordinates(waypoint);
			if (projection.isVisible()) {
				float x = projection.getX();
				float y = - projection.getY();
				canvas.drawCircle(x, y, 4, paint);
				canvas.drawText(waypoint.getName(), x, y - b - 4, paint);
			}
		}
		/* my location */
		if (projection.isVisible()) {
			canvas.save();
			projection.calcCoordinates(actualLocation);
			canvas.translate(projection.getX(), - projection.getY());
			if (actualLocation.getSpeed() * 3.6f < 10f) {
				canvas.rotate(-compass);
			} else {
				canvas.rotate(-actualLocation.getBearing());
			}
			paint.setColor(0xcc00ff00);
			Path path = new Path();
			path.moveTo(0, 0);
			path.rLineTo(-10, -7);
			path.rLineTo(10, 25);
			path.rLineTo(10, -25);
			path.rLineTo(-10, 7);
			canvas.drawPath(path, paint);
			canvas.restore();
		}
		canvas.restore();
		/* draw compass */
		if (showCompas) {
			canvas.save();
			canvas.translate(width - 25, 25);
			paint.setColor(0xcc00aaff);
			paint.setStyle(Style.STROKE);
			canvas.rotate(mapRotate + 180);
			Path path = new Path();
			path.moveTo(-7, -20);
			path.rLineTo(7, 42);
			path.rLineTo(7, -42);
			path.rLineTo(-14, 0);
			canvas.drawPath(path, paint);
			canvas.restore();
		}
		/* draw speed */
		paint.setStyle(Style.FILL);
		paint.setTextSize(32);
		paint.setTypeface(Typeface.DEFAULT_BOLD);
		paint.setTextAlign(Paint.Align.LEFT);
		paint.setColor(0xff33ccff);
		String speed = "" + (int)(actualLocation.getSpeed() * 3.6f);
		canvas.drawText(speed, 4, 4 - paint.getFontMetrics().top, paint);
		float sw = paint.measureText(speed);
		paint.setTypeface(Typeface.DEFAULT);
		paint.setTextSize(16);
		canvas.drawText("km/h", 6 + sw, 4 - paint.getFontMetrics().top, paint);
		/* gps status */
//		if (noFix) { 
//			paint.setStyle(Style.FILL);
//			paint.setTextSize(24);
//			paint.setTypeface(Typeface.DEFAULT);
//			paint.setTextAlign(Paint.Align.CENTER);
//			paint.setColor(0xffff7700);
//			canvas.drawText("NO FIX", width / 2, 4 - paint.getFontMetrics().top, paint);
//		}
		/* draw bottom panel */
		paint.setStyle(Style.FILL);
		paint.setTextSize(13);
		paint.setTextAlign(Paint.Align.LEFT);
		paint.setTypeface(Typeface.DEFAULT);
		paint.setColor(0xff333333);
		canvas.drawRoundRect(new RectF(0, getHeight() - 6 + paint.getFontMetrics().top, width, height), 4, 4, paint);
		paint.setColor(0xffccccff);
		if (actualLocation != null) canvas.drawText(Coordinates.convert(actualLocation.getLongitude(), Coordinates.FORMAT_SECONDS, Coordinates.TYPE_LONGITUDE) + "  " + Coordinates.convert(actualLocation.getLatitude(), Coordinates.FORMAT_SECONDS, Coordinates.TYPE_LATITUDE) + "  alt:" + (int)actualLocation.getAltitude() + "m  acc:" + (int)actualLocation.getAccuracy() + "m", 4, height - paint.getFontMetrics().bottom - 3, paint);
		/* OSD */
		osd.onDraw(canvas);
	}

	private boolean mapTouchDown;
	private Coordinates mapTouchDownCoordinates;
	private Coordinates lastCenter;
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		if (osd.onEvent(event)) return true;
		float x0 = event.getX() - getWidth() / 2;
		float y0 = getHeight() / 2 - event.getY();
		float v = FloatMath.sqrt(x0 * x0 + y0 * y0);
		float u = (float)(Math.atan2(y0, x0) * 180 / Math.PI);
		u += mapRotate;
		float x = v * FloatMath.cos(u * (float)Math.PI / 180f);
		float y = v * FloatMath.sin(u * (float)Math.PI / 180f);
		switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN :
				if (projection.getZoom() * getHeight() * 2 > Coordinates.REARTH) {
					float r = (float)(Coordinates.REARTH / projection.getZoom());
					if (r * r < x * x + y * y) {
						return false;
					}
				}
				mapTouchDown = true;
				mapTouchDownCoordinates = projection.getCoordinates(x, y);
				lastCenter = projection.getCenter();
				return true;
			case MotionEvent.ACTION_MOVE :
				if (mapTouchDown) {
					followLocation = false;
					if (projection.getZoom() * getHeight() * 2 > Coordinates.REARTH) {
						float r = (float)(Coordinates.REARTH / projection.getZoom());
						if (r * r < x * x + y * y) {
							return false;
						}
					}
					Coordinates mapTouchDownCoordinates2 = projection.getCoordinates(x, y);
					Coordinates diff = mapTouchDownCoordinates2.sub2(mapTouchDownCoordinates);
					projection.setCenter(lastCenter.sub2(diff));
					Log.d(TAG, projection.getCenter().toString());
					invalidate();
				}
				return true;
			case MotionEvent.ACTION_UP :
				if (mapTouchDown) {
					mapTouchDown = false;
					return true;
				}
				return false;
			case MotionEvent.ACTION_CANCEL :
			case MotionEvent.ACTION_OUTSIDE :
				if (mapTouchDown) {
					mapTouchDown = false;
					return true;
				}
				return false;
		}
		return false;
	}

	@Override
	public boolean onButtonEvent(OsdWidget osdButton, int event) {
		if (osdButton == zoomin && event == OsdButtonEvent.DOWN) {
			projection.zoom(1/1.2f);
			invalidate();
		} else if (osdButton == zoomout && event == OsdButtonEvent.DOWN) {
			projection.zoom(1.2f);
			invalidate();
		} else if (osdButton == rotateright && event == OsdButtonEvent.DOWN) {
			mapRotate += 5f;
			invalidate();
		} else if (osdButton == rotateleft && event == OsdButtonEvent.DOWN) {
			mapRotate -= 5f;
			invalidate();
		} else return false;
		return true;
	}

}
